//IPT implemenation
#include "ipt.h"
#include "system.h"

using namespace std;

IPT::IPT()
{
	iptTable = new IPTentry[NumPhysPages];
	currentListSize = 0;
	iptLock = new Lock ("IPT Lock");
}

IPT::~IPT()
{
	delete iptTable;
	delete iptLock;
}

void IPT::Assign(int physical,int incomingVirtual, int processId)
{
	//iptLock->Acquire();
	int* listValue;
	if(currentListSize < NumPhysPages)
	{
		listValue = new int(physical);
		fifoList.Append((void*)listValue);
	}
	iptTable[physical].SetPhysical(physical);
	iptTable[physical].SetVirtual(incomingVirtual);
	iptTable[physical].SetProcessId(processId);
	iptTable[physical].MakeValid();
	//iptLock->Release();
}

void IPT::DeallocateSpace(AddrSpace* space)
{
	//iptLock->Acquire();
	int id = processTable->Get_Process_Id(space);
	for (int i = 0; i < NumPhysPages; i++)
	{
		if (iptTable[i].GetId() == id)
		{
			iptCheck->Clear(i);
			iptTable[i].Reset();
		}
	}
	//iptLock->Release();
}

void IPT::DeallocateThread(AddrSpace* space, int topOfStack)
{
	//iptLock->Acquire();
	int id = processTable->Get_Process_Id(space);
	for (int i = 0; i < NumPhysPages; i++)
	{
		if ((iptTable[i].GetId() == id) && (iptTable[i].GetVirtual() >= (topOfStack-8) && iptTable[i].GetVirtual() < (topOfStack)) )
		{
			iptCheck->Clear(i);
			iptTable[i].Reset();
		}
	}
	//iptLock->Release();
}

void IPT::Update(int physical, int incomingVirtual, int processId)
{
	//iptLock->Acquire();
	iptTable[physical].SetPhysical(physical);
	iptTable[physical].SetVirtual(incomingVirtual);
	iptTable[physical].SetProcessId(processId);
	iptTable[physical].MakeClean();
	iptTable[physical].MakeValid();
	//iptLock->Release();
}

void IPTentry::PopulateTLB()
{
	IntStatus oldInterruptState = interrupt->SetLevel(IntOff);
	machine->tlb[tlbCounter].virtualPage = virtualPage;
	machine->tlb[tlbCounter].physicalPage = physicalPage;
	machine->tlb[tlbCounter].valid = valid;
	machine->tlb[tlbCounter].use = use;
	machine->tlb[tlbCounter].dirty = dirty;
	machine->tlb[tlbCounter].readOnly = readOnly;
	(void) interrupt->SetLevel(oldInterruptState);
}

void IPTentry::Reset()
{
	dirty = false;
	valid = false;
	readOnly = false;
	use = false;
	processId=0;
	physicalPage = -1;
	virtualPage = -1;
}

void IPT::PopulateTLBSearch(int vpn, int id)
{
	//iptLock->Acquire();
	int i=0;
	for (; i<NumPhysPages; i++)
	{
		if (iptTable[i].GetVirtual() == vpn)
			//printf("memory index to populate but wrong process: %i,process:%i\n", i,iptTable[i].GetId());
		if (iptTable[i].GetVirtual() == vpn && iptTable[i].GetId() == id)
		{
			iptTable[i].PopulateTLB();
			break;
		}
	}
	//iptLock->Release();
}

int IPT::FIFO()
{
	iptLock->Acquire();
	int* listValue = (int*)fifoList.Remove();
	fifoList.Append((void*)listValue);
	iptLock->Release();
	return *listValue;
}

IPTentry::IPTentry()
{
	dirty = false;
	valid = false;
	readOnly = false;
	use = false;
	processId=0;
	physicalPage = -1;
	virtualPage = -1;
}

IPTentry::~IPTentry()
{


}